package cn.hh.ymcc.service.impl;

import cn.hh.ymcc.constants.CommonConstants;
import cn.hh.ymcc.constants.SmsCodeConstants;
import cn.hh.ymcc.constants.YmccError;
import cn.hh.ymcc.constants.dto.RedisRegisterDto;
import cn.hh.ymcc.domain.MessageBlacklist;
import cn.hh.ymcc.domain.MessageSms;
import cn.hh.ymcc.exception.GlobalException;
import cn.hh.ymcc.mapper.MessageBlacklistMapper;
import cn.hh.ymcc.mapper.MessageSmsMapper;
import cn.hh.ymcc.result.JSONResult;
import cn.hh.ymcc.service.IMessageBlacklistService;
import cn.hh.ymcc.service.IMessageEmailService;
import cn.hh.ymcc.service.IMessageSmsService;
import cn.hh.ymcc.service.IVerifyCodeService;
import cn.hh.ymcc.util.AssertUtil;
import cn.hh.ymcc.util.StrUtils;
import cn.hh.ymcc.vo.MessageSmsVO;
import com.sun.media.sound.SoftTuning;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.statement.insert.Insert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j // 注入日志
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Autowired
    private IMessageSmsService messageSmsService;  // 注入短信验证码Service

    @Autowired
    private SmsCodeConstants smsCodeConstants;

    @Autowired
    private IMessageBlacklistService  messageBlacklistService;

    @Autowired
    private MessageBlacklistMapper blacklistmapper;


//    @Value("${register.smscode.interval}")
//    private Integer integer;

    @Override
    public void smsCode(String mobile) {
        // 1.非空校验
        AssertUtil.isNotEmpty(mobile,YmccError.COMMON_PHONE_NO_EMPTY.getMessage());  // 断言手机号不为空,为空就抛错
//        if (StringUtils.isEmpty(mobile)) {
//            // 如果为空就抛异常提醒
//            throw new GlobalException(YmccError.COMMON_PHONE_NO_EMPTY.getMessage(),
//                                      YmccError.COMMON_PHONE_NO_EMPTY.getCode());
//        }
        // 1.1.格式校验 @TODO  黑名单
        AssertUtil.isPhone(mobile,YmccError.COMMON_PHONE_ILLEGAL.getMessage());  // 断言手机格式必须合法
        // 验证码
        // 创建一个key对象
        String key = String.format(CommonConstants.REGISTER_PHONE_PRIFIX,mobile); // register:1008611....
        // 创建一个时间对象
        Date now = new Date();
        // 校验手机号是否发送过验证码
        Object o = redisTemplate.opsForValue().get(key); // redis中查验证码
        String code = null;
        if (o != null) {
            // 2.从redis拿到了验证码
            RedisRegisterDto registerDto = (RedisRegisterDto) o;  // 将o强转 短信验证码实体类
            // 2.1.没有过重发时间
            boolean canSend = (now.getTime() - registerDto.getTime()) / 1000 > smsCodeConstants.getInterval(); // 判断当前时间/1000秒,大于1分钟(Interval:yml配置的常量) 可以重新发送验证码了
            AssertUtil.isTrue(canSend,YmccError.COMMON_SERIOUS.getMessage()); // 断言必须是true,不然就抛错

//            if ((now.getTime() - registerDto.getTime()) / 1000 < smsCodeConstants.getInterval()) {  // 判断当前时间减去上次时间,小于1分钟 没有过重发验证码时间
//                throw new GlobalException(YmccError.COMMON_SERIOUS.getMessage(),YmccError.COMMON_SERIOUS.getCode());
//            }
            // 2.2.过了重发时间,使用还未过期的验证码
            code = registerDto.getCode();

            // 3.拿不到验证码
        }else{
            // 3.1.生成验证码
            code = StrUtils.getRandomString(smsCodeConstants.getSize());// 使用工具类调用随机验证码方法
        }

        // 4. 存储验证码到Redis
        // 4.1.使用RedisRegisterDto,传入Code验证码对象,时间戳
        RedisRegisterDto redisRegisterDto = new RedisRegisterDto(code, now.getTime());
        // 4.2.Redis存入验证码,时间戳对象,和过期时间
        redisTemplate.opsForValue().set(key, redisRegisterDto, smsCodeConstants.getTimeOut(), TimeUnit.SECONDS);
        // 4.3.发送短信验证码
        String message = String.format(smsCodeConstants.getSmsmessage(), code);
        log.info(message, code);
        // 4.4.存储发送信息到数据库
        saveMessageSms(now,code,message); // 调用下面的方法存储
    }



    /**
     *  添加黑名单
     * @param messageSms
     */
    @Override
    public JSONResult saveblacklist(MessageSmsVO messageSms) {
        String blacklistKey = "blacklist" + messageSms.getUserId();
        // 2.获取到userId对象
        MessageBlacklist userBlacklistDB = blacklistmapper.selectByUserId(messageSms.getUserId());
        // 3.将userId对象做判断
        if (userBlacklistDB != null && userBlacklistDB.getUser() != null){
            // 如果存在直接return
            return JSONResult.error("用户已存在黑名单");
        } // 4.不存在就添加进黑名单
        // 4.1.保存黑名单的数据
        MessageBlacklist blacklist = new MessageBlacklist();
        blacklist.setUser(messageSms.getUserId()); // 设置用户id
        blacklist.setPhone(messageSms.getPhone()); // 设置 用户手机号
        blacklist.setIp(messageSms.getIp()); // 设置 用户手机号
        blacklist.setAddtime(new Date()); // 设置拉黑时间
        // 使用请求上下文工具:拿到Attributes
//        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
//        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest(); // 将requestAttributes强转为ServletRequestAttributes,获取Request
//        userBlacklist.setIp(request.getRemoteAddr()); // 设置ip地址
        boolean insert = messageBlacklistService.insert(blacklist);
        if (!insert) return JSONResult.error("保存失败!");
        return JSONResult.success();
    }


    /**
     *  将发送信息存储到数据库,抽取为一个方法
     * @param now
     * @param code
     */
    private void saveMessageSms(Date now, String code,String message) {
        MessageSms messageSms = new MessageSms();  // 创建一个短信验证码对象
        messageSms.setContent(message); // 短信验证码对象设置内容: code
        messageSms.setSendTime(now);  // 短信验证码对象设置时间: now
        messageSms.setTitle(smsCodeConstants.getTitle());  // 短信验证码对象设置Title
        // 使用请求上下文工具:拿到Attributes
        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest(); // 将requestAttributes强转为ServletRequestAttributes,获取Request
        messageSms.setIp(request.getRemoteAddr());  // 获取IP地址
        messageSmsService.insert(messageSms);
    }
}




